#|____________________________________________
 |
 | HOW TO WRITE THE PLUGIN INTERFACE
 |   The plugin interface consists, in part, 
 |   of the following plugin loader function.
 | This code is explained below.
 |____________________________________________
 |#

#|________________________________________________________________________
 |
 | Principal Components Plugin Loading Function
 |________________________________________________________________________
 |#


(setf *pca-plugin-path* (strcat *plugin-path* "pcaplug" *separator*))
(let ((menu-item-title "Principal Components")
      (tool-name "PrnCmp")
      (model-prefix "PCA")
      (ok-data-types '("multivariate" "crosstabs" "general"))
      (ok-variable-types '(numeric)))

  (send *vista* :install-plugin tool-name menu-item-title ok-data-types)

  (defun principal-components 
    (&key 
;; unique keyword arguments for this plugin
     (covariances nil)
;; universal keywords used by all plugins
     (data   *current-data*)
     (title  menu-item-title)
     (name   tool-name)
     (dialog t))
"ViSta plugin function to perform Principal Components analysis.  
With no arguments, calculate correlations among all active numeric variables in the current data and perform a principal components analysis.
Keyword arguments are:
:COVARIANCES followed by 
   t    causes the analysis to be performed on covariances, or 
   nil  causes the analysis to be performed on correlations, the default.
:DATA   followed by the data-object to be analyzed (default: *current-data*)
:TITLE  followed by a character string (default: \"Principal Components\")
:NAME   followed by a character string (default: \"PrnCmp\")
:DIALOG followed by t (to display parameters dialog box) or nil (default)"
    (format t "; CopyRt: PRNCMP Copyright (c) 1992-2002, by Forrest W. Young~%> ")
    (load (strcat *pca-plugin-path* "pcamob"))
    (principal-components
     covariances
     menu-item-title tool-name model-prefix ok-data-types 
     data title name dialog ok-variable-types))
  )


#|____________________________________________
 |
 | ON WRITING A VISTA PLUGIN
 |____________________________________________

The ViSta plugin interface consists of two short pieces of code.  One piece is the plugin loader, which comprises the entire execuatable contents of the plugin loader file, The other piece is the plugin constructor function, which is an even smaller piece of code that is loacated at the beginning of the file which is the main entry point to the rest of the code. This file is called the plugin constructor file.  This file must also contain statements which will load in the remainder of the code, if necessary.

The Lisp code file that you locate in ViSta's plugin directory is the file that interfaces your plugin's code with ViSta and its plugin system. All files in the PLUGIN directory are automatically loaded in by ViSta, and all these files must be PLUGIN INTERFACE files only. The main body of your plugin's code resides in a subdirectory of the PLUGIN directory. The code in a subdirectory is not automatically loaded by ViSta: You have to write the code to make it load.

CODE RESTRICTION: Currently, your code must not contain any symbols which redefine symbols in ViSta. It is best if your code consists entirely of object-oriented code. In particular, avoid the use of DEFUN. If you must use DEFUN, make sure first that there isn't already a function with the same name. 

The plugin interface code must follow the three steps shown here. An example is developed as this document unfolds. 

 |____________________________________________
 |
 | STEP 1: DEFINE THE PLUGIN'S SYSTEM VARIABLES
 |____________________________________________
 |

Begin with a statement that defines the location of the file containing the constructor function. The filename must simultaneously follow the rules of directory naming for the MSDOS, MACINTOSH and UNIX operating systems. The file must be a .lsp file. For our principal components example this statement is:

(setf *pca-plugin-path* (strcat *plugin-path* "pcaplug" *separator*))

Your plugin constructor file MUST be located in a subdirectory of the plugin directory. The file must contain the plugin's constructor function. If all the code doesn't fit in one file, the entry file must load in the additional files that are needed. They are not loaded in by ViSta.

Now we need to define five local variables:
      
1) MENU-ITEM-TITLE - Specifies the plugin's menu item title (a string of up to approximately 10 to 20 characters)

2) TOOL-NAME - Specifies the plugin's tool name on the toolbar (a string of 5 or 6 characters)

3) MODEL-PREFIX-NAME - Specifies the plugin's name on the workmap (a string of 3 characters)

4) OK-VARIABLE-TYPES - Specifies the data types that are used by the plugin. The possible ok-variable-types are "numeric" and "category". The "ordinal" type is not supported.

5) OK-DATA-TYPES - Specifies the data types that are used by the plugin (a string list). Datatypes are discussed in one of the help topics.

 |____________________________________________
 |
 | STEP 2: CONFIGURE VISTA'S PLUGIN SYSTEM 
 |         FOR YOUR PLUGIN
 |____________________________________________
 |

This step configures ViSta's plugin system for your plugin. The step consists of using the following statement, which should be copied into your code verbatim:


At this point we have

(setf *pca-plugin-path* (strcat *plugin-path* "pcaplug" *separator*))
(let* ((menu-item-title     "Principal Components")
       (tool-name           "Prncmp"              )
       (model-prefix-name   "PCA"                 )
       (ok-variable-types '("numeric")            )
       (ok-data-types     '("multivariate" "crosstabs" "general"))
       )
  (send *vista* :install-plugin tool-name menu-item-title ok-data-types)

 |____________________________________________
 |
 | STEP 3: DEFINE THE PLUGIN'S LOADER AND CONSTRUCTOR FUNCTIONS
 |____________________________________________
 |


You must write two functions which have identical names but different arguments and bodies. One of these two functions is loaded when ViSta is run, while the other is loaded the first time the user needs to use the plugin.

The function that is loaded when ViSta is run is called the PLUGIN LOADER FUNCTION since it's primary purpose is to load the plugin's code the first time the user needs to use the plugin. The loader function is a small piece of code written according to rules specified here. It is contained in your plugin loader file (the file you place in the PLUGINS directory). 

The function that does the analysis is called the PLUGIN CONSTRUCTOR FUNCTION because it constructs an instance of the plugin object whenever the user uses the plugin. It is the function which serves as the entry point to your plugin's code. It must be located in the PLUGIN-ENTRY-FILE with the code that is read in by the loader function. This code must be in a subdirectory of the plugins directory. There can be any number of code files, but you must explicitly load all of them with LOAD or REQUIRE statements in the PLUGIN-ENTRY-FILE.

Because the loader and constructor functions have the same name, and because the code read in by the loader function contains the constructor function, the loader function modifies itself to become the constructor function (i.e., the loader function is self-modifying). The architecture of the constructor function is as it is so that code to do the analysis is not loaded until needed. Note, however, that the menu item, tool and model prefix are automatically loaded at startup.

Here are the rules:

0) The loader and constructor functions MUST have the same names.

1) The loader function arguments are a proper subset of
   the constructor function arguments. 

2) The loader and constructor functions MUST have the following keyword arguments:
   data    symbol  bound to *current-data* (also known as $)
   title   string  bound to menu-item-title
   name    string  bound to tool-name
   dialog  logical bound to t if the analysis dialog is shown, nil if not

3) The loader and the constructor function MAY have any number of additional arguments as is needed by your analysis. 

4) The constructor function has addition undocumented arguments which are the plugin file and system variables.
 
5) The loader function MUST take these following two actions in the order specified:
   A: load in code from the plugin path. This code MUST contain the constructor function.
   B: issue a call to the constructor function. 
The loader function should include a documentation string (which documents all arguments except the undocumentd ones) and a copyright notice.

For our principal components example, the loader function is:


(setf *pca-plugin-path* (strcat *plugin-path* "pcaplug" *separator*))
(let* ((menu-item-title     "Principal Components")
       (tool-name           "Prncmp"              )
       (model-prefix-name   "PCA"                 )
       (ok-variable-types '("numeric")            )
       (ok-data-types     '("multivariate" "crosstabs" "general")))
  (send *vista* :install-plugin   tool-name        menu-item-title   ok-data-types)  

  (defun principal-components 
    (&key 
     (covariances nil)        ;unique argument used by this plugin
     (data   *current-data*)  ;system argument used by all  plugins
     (title  menu-item-title) ;system argument used by all  plugins
     (name   tool-name)       ;system argument used by all  plugins
     (dialog t))
"ViSta plugin loader function to load the code into ViSta which performs Principal Components analysis. The code is loaded only when needed.
With no arguments, calculate correlations among all active numeric variables in the current data and perform a principal components analysis.
Keyword arguments are:
:COVARIANCES followed by 
          t   causes the analysis to be performed on covariances, or 
          nil causes the analysis to be performed on correlations, the default.
:DATA   followed by the data-object to be analyzed (default: *current-data*)
:TITLE  followed by a character string (default: \"Principal Components\")
:NAME   followed by a character string (default: \"PrnCmp\")
:DIALOG followed by t (to display parameters dialog box) or nil (default)"
    (princ ";CopyRt: Principal Components code Copyright (c) 1992-2002, by Forrest W. Young")
    (terpri)
    (load plugin-entry-file)
    (principal-components
     :covariances covariances
     :data data
     :title title
     :name name
     :dialog dialog
     :menu-item-title menu-item-title
     :tool-name tool-name 
     :model-prefix model-prefix
     :ok-data-types ok-data-types
     :ok-variable-types ok-variable-types))

  );ends the let* statement





|________________________________________________________________________
 |
 | ABOUT THE PLUGIN'S NEW MESSAGE AND :ISNEW METHOD
 |________________________________________________________________________
 

The plugin's :new message and :isnew method MUST have the following arguments which MUST be in exactly the order stated here:
1) The arguments unique to this plugin are specified first.
2) The plugin system arguments are specifed next. They must be specified in exactly the order used here. They are
           menu-item-title 
           tool-name 
           model-prefix 
           ok-data-types
           data 
           title 
           name 
           dialog  
           ok-variable-types

The new messsage is, then:
(send pca-model-object-proto :new
      (not covariances) menu-item-title tool-name model-prefix ok-data-types 
      data title name dialog ok-variable-types))
The :isnew method is defined accordingly.  Here is the entire constructor method:

(let ((menu-item-title "Principal Components")
      (tool-name "PrnCmp")
      (model-prefix "PCA")
      (ok-data-types '("multivariate" "general"))
      (ok-variable-types '(numeric)))

  (defun principal-components 
    (&key 
;; unique keyword arguments for this plugin
     (covariances nil)
;; universal keywords used by all plugins
     (data   *current-data*)
     (title  menu-item-title)
     (name   tool-name)
     (dialog nil))
"ViSta function to perform Principal Components analysis.  
With no arguments, calculate correlations among all active numeric variables in the current data and perform a principal components analysis.
Keyword arguments are:
:COVARIANCES followed by 
   t    causes the analysis to be performed on covariances, or 
   nil  causes the analysis to be performed on correlations, the default.
:DATA   followed by the data-object to be analyzed (default: *current-data*)
:TITLE  followed by a character string (default: \"Principal Components\")
:NAME   followed by a character string (default: \"PrnCmp\")
:DIALOG followed by t (to display parameters dialog box) or nil (default)"
    (send pca-model-object-proto 
          :new (not covariances)
          menu-item-title tool-name model-prefix ok-data-types 
          data title name dialog ok-variable-types))
  )



The remainder of the code is specific to your particular plugin. If the code doesn't fit in one file, then the additional files must be in a subdirectory and then loaded after the constructor function and :isnew method are defined. 

|#